package com.hkj.configcenter.admin.controller;

import com.github.zkclient.ZkClient;
import com.hkj.configcenter.admin.url.PageUrl;
import com.hkj.configcenter.admin.url.ServiceUrl;
import com.hkj.configcenter.admin.vo.ResponseDTO;
import com.hkj.configcenter.admin.vo.SysUser;
import com.hkj.configcenter.admin.vo.Tree;
import com.hkj.configcenter.core.Context;
import com.hkj.configcenter.core.processor.ZkProcessor;
import com.hkj.configcenter.core.utils.ZkUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.zookeeper.data.Stat;
import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;

import java.text.SimpleDateFormat;
import java.util.*;
import java.util.concurrent.atomic.AtomicLong;

@Slf4j
@Controller
public class ConfigCenterController {

    static AtomicLong id = new AtomicLong(0);

    @GetMapping(ServiceUrl.CONFIG_CENTER_HOME)
    public String home(ModelMap modelMap) {
        Tree root = new Tree();
        root.setName("配置服务");
        root.setIcon("fa fa-diamond");
        root.setUrl(Context.getConfigRootPath());

        List<String> projectNames = Context.zkClient.getChildren(Context.getConfigRootPath());
        Collections.sort(projectNames, Context.STRING_COMPARATOR);
        log.info("配置环境列表 = {}", projectNames);
        for (String projectName : projectNames) {
            Tree tree = new Tree();
            tree.setName(projectName);
            tree.setUrl(Context.getConfigRootPath() + "/" + projectName);
            String[] values = ZkUtils.readTextRemark(tree.getUrl());
            tree.setText(values[0]);
            tree.setRemark(values[1]);
            tree.setUrl(ServiceUrl.CONFIG_CENTER_ENV + "?url=" + tree.getUrl());
            root.addChildren(tree);
        }

        modelMap.put("menus", Arrays.asList(root));
        modelMap.put("user", new SysUser());
        modelMap.put("copyrightYear", "2019-wxhua");
        modelMap.put("demoEnabled", "demoEnabled");
        return PageUrl.CONFIG_CENTER_HOME_PAGE;
    }

    @GetMapping(ServiceUrl.CONFIG_CENTER_ENV)
    public String env(String url, ModelMap modelMap) {
        modelMap.put("url", url);
        modelMap.put("env", ZkUtils.getEnvByPath(url));
        return "config-center-env";
    }

    @PostMapping(ServiceUrl.CONFIG_CENTER_ENV)
    @ResponseBody
    public List<Tree> env(String url, String name) {
        List<Tree> list = new ArrayList<>();
        List<String> projectNames = Context.zkClient.getChildren(url);
        Collections.sort(projectNames, Context.STRING_COMPARATOR);
        log.info("配置环境列表 = {}", projectNames);

        for (String projectName : projectNames) {
            Tree tree = new Tree();
            tree.setName(projectName);
            tree.setUrl(url + "/" + projectName);
            String[] values = ZkUtils.readTextRemark(tree.getUrl());
            tree.setText(values[0]);
            tree.setRemark(values[1]);
            list.add(tree);
        }

        return list;
    }

    @GetMapping(ServiceUrl.CONFIG_CENTER_DETAIL)
    public String detail(String url, ModelMap modelMap) {
        modelMap.put("url", url);
        return PageUrl.CONFIG_CENTER_DETAIL_PAGE;
    }

    @PostMapping(ServiceUrl.CONFIG_CENTER_DETAIL)
    @ResponseBody
    public List<Tree> detail(String url, String name) {
        log.info("【查看服务】url={}", url);
        List<Tree> list = new ArrayList<>();
        if (StringUtils.isEmpty(url)) {
            return list;
        }

        if (!url.endsWith(Context.getCommonConfig())) {
            getChildrenValue(Context.zkClient, null, Context.getConfigRootPath() + "/" + ZkUtils.getEnvByPath(url) + Context.getCommonConfig(), 0, 3, list);
        }
        getChildrenValue(Context.zkClient, null, url, 0, 3, list);

        if (StringUtils.isEmpty(name)) {
            return list;
        }

        List<Tree> target = new ArrayList<>();
        for (Tree sysMenu : list) {
            if (sysMenu.getName().contains(name)) {
                target.add(sysMenu);
            }
        }
        return target;
    }

    @GetMapping(ServiceUrl.CONFIG_CENTER_NODE_ADD)
    public String add(String url, String type, ModelMap mm) {
        mm.put("url", url);
        if("modify".equals(type)) {
            List<String> envs = Context.zkClient.getChildren(Context.getConfigRootPath());
            Collections.sort(envs, Context.STRING_COMPARATOR);
            mm.put("envs", envs);
        }
        return "config-center-add";
    }

    @PostMapping(ServiceUrl.CONFIG_CENTER_NODE_ADD)
    @ResponseBody
    public ResponseDTO add(String url, String name, String text, String remark) throws Exception {
        log.info("【配置中心】新增url={},name={},text={},remark={}", url, name, text, remark);
        name = name.trim();
        if (StringUtils.isEmpty(name)) {
            return new ResponseDTO(-1, "失败");
        }

        String value = text.trim() + (StringUtils.isEmpty(remark) ? "" : Context.SPLIT_FLAG + remark);
        if(Context.zkClient.exists(url + "/" + name)) {
            Context.zkClient.writeData(url + "/" + name, value.getBytes("UTF-8"));
        } else {
            Context.zkClient.createPersistent(url + "/" + name, value.getBytes("UTF-8"));
        }
        return new ResponseDTO(0, "成功");
    }

    @GetMapping(ServiceUrl.CONFIG_CENTER_NODE_MODIFY)
    public String modify(String url, ModelMap mm) throws Exception {
        Stat stat = Context.zkClient.getZooKeeper().exists(url, false);
        Tree detail = new Tree();
        detail.setName(ZkProcessor.getKey(url));
        String[] values = ZkUtils.readTextRemark(url);
        detail.setText(values[0]);
        detail.setRemark(values[1]);
        detail.setUrl(url);
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        detail.setCreateTime(sdf.format(new Date(stat.getCtime())));
        detail.setUpdateTime(sdf.format(new Date(stat.getMtime())));
        mm.put("menu", detail);

        if(url.contains(Context.ONLINE_MACHINES)) {
            return "config-center-detail";
        }
        return "config-center-edit";
    }

    @GetMapping(ServiceUrl.CONFIG_CENTER_NODE_DETAIL)
    public String nodeDetail(String url, ModelMap mm) throws Exception {
        Stat stat = Context.zkClient.getZooKeeper().exists(url, false);
        Tree detail = new Tree();
        detail.setName(ZkProcessor.getKey(url));
        String[] values = ZkUtils.readTextRemark(url);
        detail.setText(values[0]);
        detail.setRemark(values[1]);
        detail.setUrl(url);
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        detail.setCreateTime(sdf.format(new Date(stat.getCtime())));
        detail.setUpdateTime(sdf.format(new Date(stat.getMtime())));
        mm.put("menu", detail);
        return "config-center-detail";
    }

    @ResponseBody
    @PostMapping(ServiceUrl.CONFIG_CENTER_NODE_MODIFY)
    public ResponseDTO modify(String url, String text, String remark) throws Exception {
        log.info("【配置中心修改】url={},text={},remark={}", url, text, remark);
        url = url.trim();
        if (StringUtils.isEmpty(url)) {
            return new ResponseDTO(-1, "失败");
        }

        String value = text.trim() + (StringUtils.isEmpty(remark) ? "" : Context.SPLIT_FLAG + remark);
        Context.zkClient.writeData(url, value.getBytes("UTF-8"));
        return new ResponseDTO(0, "成功");
    }

    @ResponseBody
    @GetMapping(ServiceUrl.CONFIG_CENTER_NODE_DEL)
    public ResponseDTO remove(String url) {
        List<String> children = Context.zkClient.getChildren(url);
        if (children.size() > 0) {
            return new ResponseDTO(-1, "【防止误删】请先将子节点都全部删除后再删除父节点");
        }

        Context.zkClient.deleteRecursive(url);
        return new ResponseDTO(0, "成功");
    }

    @ResponseBody
    @GetMapping(ServiceUrl.CONFIG_CENTER_NODE_DELREC)
    public ResponseDTO removeRec(String url) {
        Context.zkClient.deleteRecursive(url);
        return new ResponseDTO(0, "成功");
    }

    @PostMapping(ServiceUrl.CONFIG_CENTER_PUBLISH)
    @ResponseBody
    public ResponseDTO publish(@RequestParam("path") String path) throws Exception {
        log.info("【配置中心发布】path={}", path);
        path = path + Context.ONLINE_MACHINES;
        String data = ZkUtils.readData(Context.zkClient, path);

        if (StringUtils.isEmpty(data)) {
            log.info("【配置中心发布】data为空", path);
            return new ResponseDTO(-1, "发布失败,data为空");
        }

        Integer modifyData = 1;
        try {
            modifyData = Integer.parseInt(data) + 1;
        } catch (Exception e) {
            modifyData = 1;
        }

        Context.zkClient.writeData(path, modifyData.toString().getBytes());
        log.info("【配置中心发布】path={}, modifyData={}", path, modifyData);

        Thread.sleep(200);
        return new ResponseDTO(0, "发布成功");
    }

    private static void getChildrenValue(ZkClient zkClient, Tree parentTree, String currentPath, int currentLevel, int closeLevel, List<Tree> list) {
        currentLevel++;
        List<String> children = zkClient.getChildren(currentPath);

        if (children.size() > 0) {
            Tree parentNode = new Tree();
            parentNode.setName(ZkProcessor.getKey(currentPath));
            parentNode.setUrl(currentPath);
            parentNode.setMenuId(id.incrementAndGet());
            parentNode.setParentId(parentTree == null ? 0 : parentTree.getMenuId());
            String[] values = ZkUtils.readTextRemark(currentPath);
            parentNode.setText(values[0]);
            parentNode.setRemark(values[1]);
            list.add(parentNode);

            Collections.sort(children, Context.STRING_COMPARATOR);
            for (String child : children) {
                getChildrenValue(zkClient, parentNode, currentPath + "/" + child, currentLevel, closeLevel, list);
            }

        } else {
            Tree tree = new Tree();
            String[] values = ZkUtils.readTextRemark(currentPath);
            tree.setText(values[0]);
            tree.setRemark(values[1]);
            tree.setName(ZkProcessor.getKey(currentPath));
            tree.setUrl(currentPath);
            tree.setMenuId(id.incrementAndGet());
            tree.setParentId(parentTree == null ? 0 : parentTree.getMenuId());
            list.add(tree);
        }

    }

}
